'use strict';

const { Controller } = require('egg');
const crypto = require("crypto");
// 引入微信配置参数（上面准备工作中保存的config/wx.js文件，包含小程序id，密钥，商户id，商户密钥）
const config = require("../../config/wx");
const fs = require("fs");
const path = require('path');
function createOrderNumber() {
  // 获取当前日期和时间
  let date = new Date();
  let year = date.getFullYear();
  let month = date.getMonth() + 1; // getMonth() 是从0开始的，所以需要+1
  let day = date.getDate();
  let hours = date.getHours();
  let minutes = date.getMinutes();
  let seconds = date.getSeconds();

  // 格式化日期和时间
  month = month < 10 ? '0' + month : month; // 如果月份小于10，前面添加一个0
  day = day < 10 ? '0' + day : day; // 如果日期小于10，前面添加一个0
  hours = hours < 10 ? '0' + hours : hours; // 如果小时小于10，前面添加一个0
  minutes = minutes < 10 ? '0' + minutes : minutes; // 如果分钟小于10，前面添加一个0
  seconds = seconds < 10 ? '0' + seconds : seconds; // 如果秒数小于10，前面添加一个0

  // 创建报名号
  return year + '' + month + '' + day + '' + hours + '' + minutes + '' + seconds;
}
function generateNonceStr(len) {
  let data = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678";
  let str = "";
  for (let i = 0; i < len; i++) {
    str += data.charAt(Math.floor(Math.random() * data.length));
  }
  return str;
}

class RouterController extends Controller {
  async order() {
    const { tradeNo, openid } = await this.createOrder()
    // egg框架写法
    const { service, request } = this.ctx;
    // 获取前端传入参数
    const { total_fee, body } = request.body;
    // 生成订单号（保证唯一性：我采用时间戳拼6位随机数的方式）
    const createOrderParams = {
      appid: config.appid,
      mchid: config.mch_id,
      description: body,
      out_trade_no: tradeNo,
      time_expire: new Date(Date.now() + 1000 * 60 * 30).toISOString(),
      notify_url: config.notify_url,
      amount: {
        "total" : total_fee * 100,
        "currency" : "CNY"
      },
      payer: {
        openid
      }
    }
    let timeStamp = Math.floor(new Date().getTime() / 1000)
    let nonceStr = generateNonceStr(32)
    const Authorization = `WECHATPAY2-SHA256-RSA2048 mchid="${config.mch_id}",nonce_str="${nonceStr}",signature="${this.createOrderSign('POST',
            '/v3/pay/transactions/jsapi',
            timeStamp,
            nonceStr,
            createOrderParams
        )}",timestamp="${timeStamp}",serial_no="${config.serial_no}"`
    // 下单获取prepay_id
    const createPayRes = await this.ctx.curl(
        "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi",
        {
          method: "post",
          data: createOrderParams,
          headers: {
            Authorization: Authorization,
            Accept: 'application/json',
            'Content-Type': 'application/json',
          },
          dataType: 'json'
        }
    );
    if (createPayRes.data.prepay_id) {
        // 把参数+签名返回给前端
        const result = this.createPaySign(createPayRes.data.prepay_id)
        this.ctx.success({
          ...result,
          order_no: tradeNo
        });
    } else {
      throw new Error(createPayRes.data.message);
    }
  }

  // 创建内部账号
  async createOrder() {
    const { service, request } = this.ctx;
    const { member_id, total_fee, body, report_id, research_report_id,special_report_id, nickname, phone, email, remark  } = request.body;
    // 查询用户
    const user = await service.member.findOne(member_id);
    if (user && user.openid) {
      // 生成订单号（保证唯一性：我采用时间戳拼6位随机数的方式）
      const tradeNo = createOrderNumber();
      const data = {
        order_no: tradeNo,
        member_id,
        total_price: total_fee,
        body,
        report_id,
        research_report_id,
        special_report_id,
        openid: user.openid,
        status: -1,
        nickname,
        phone,
        email,
        remark
      }
      if (body.includes('会员')) {
        await this.ctx.model.VipOrder.create(data)
      } else {
        await this.ctx.model.ReportOrder.create(data)
      }
      return {
        tradeNo,
        openid: user.openid
      }
    } else {
      throw new Error("用户不存在");
    }
  }
  /**
   * 微信支付v3 下单签名值生成
   * @param {string} method 请求方法
   * @param {string} url  微信小程序下单官方api
   * @param {number} timestamp 时间戳 秒级
   * @param {string} nonce_str 随机字符串
   * @param {Object} order 主体（订单）信息
   */
  createOrderSign(method, url, timestamp, nonce_str, order) {
    // 签名串
    let signStr = `${method}\n${url}\n${timestamp}\n${nonce_str}\n${JSON.stringify(
        order
    )}\n`;
    // 读取API证书文件内容 apiclient_key.pem的内容
    const filepath = path.join('app', '/public/apiclient_key.pem');
    let cert = fs.readFileSync(filepath, "utf-8");
    // 创建使用 RSA 算法和 SHA-256 散列算法的签名对象
    let sign = crypto.createSign("RSA-SHA256");
    // 对签名串进行加密处理
    sign.update(signStr);
    return sign.sign(cert, "base64");
  }

  createPaySign(prepay_id) {
    let timeStamp = Math.floor(new Date().getTime() / 1000)
    let nonceStr = generateNonceStr(32);
    let signStr = `${config.appid}\n${timeStamp}\n${nonceStr}\nprepay_id=${prepay_id}\n`;
    const filepath = path.join('app', '/public/apiclient_key.pem');
    let cert = fs.readFileSync(filepath, "utf-8");
    let sign = crypto.createSign("RSA-SHA256");
    sign.update(signStr);
    let paySign = sign.sign(cert, "base64");
    return {
      paySign: paySign,
      timestamp: timeStamp + '',
      nonce_str: nonceStr,
      signType: 'RSA',
      package: 'prepay_id=' + prepay_id
    };
  }

  // 微信支付回调地址
  async decodePayNotify(resource) {
    try {
      const AUTH_KEY_LENGTH = 16;
      // ciphertext = 密文，associated_data = 填充内容， nonce = 位移
      const { ciphertext, associated_data, nonce } = resource;
      // 密钥
      const key_bytes = Buffer.from('apiclient_key.pem', 'utf8');
      // 位移
      const nonce_bytes = Buffer.from(nonce, 'utf8');
      // 填充内容
      const associated_data_bytes = Buffer.from(associated_data, 'utf8');
      // 密文Buffer
      const ciphertext_bytes = Buffer.from(ciphertext, 'base64');
      // 计算减去16位长度
      const cipherdata_length = ciphertext_bytes.length - AUTH_KEY_LENGTH;
      // upodata
      const cipherdata_bytes = ciphertext_bytes.slice(0, cipherdata_length);
      // tag
      const auth_tag_bytes = ciphertext_bytes.slice(cipherdata_length, ciphertext_bytes.length);
      const decipher = crypto.createDecipheriv(
          'aes-256-gcm', key_bytes, nonce_bytes
      );
      decipher.setAuthTag(auth_tag_bytes);
      decipher.setAAD(Buffer.from(associated_data_bytes));
      const output = Buffer.concat([
        decipher.update(cipherdata_bytes),
        decipher.final(),
      ]);
      // 解密后 转成 JSON 格式输出
      return JSON.parse(output.toString('utf8'));
    }
    catch (error){
      console.error('解密错误:', error);
      return null;
    }

  }

  /**
   * 微信支付回调
   * @param {Object} req - 请求对象，包含查询参数
   * url  https://qy.xxx.com/v1/payment/wx/success
   */
  async wxnotify() {
    try {
      const { ctx } = this;
      const result = ctx.request.body;
      // 解密微信支付成功后的订单信息
      const deInfo = await this.decodePayNotify(result.resource)
      if (!deInfo) {
        throw new Error('支付回调解析失败');
      }
      //*****
      console.log('deInfo',deInfo)

      //*****
        // 返回成功
      this.ctx.success('success', 200);
    }
    catch (err) {
       this.ctx.error('支付回调错误', 500);
    }
  }
}

module.exports = RouterController;
